/*
 * Copyright (c) 2002-2003 by OpenSymphony
 * All rights reserved.
 */
package org.jackysoft.opensymphony.workflow.entity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.jackysoft.util.ValidationUtils;

import com.google.gson.annotations.Expose;


/**
 * 
 */


public class StepDescriptor extends AbstractDescriptor implements Validatable {
    //~ Instance fields ////////////////////////////////////////////////////////

    /**
	 * 
	 */
	private static final long serialVersionUID = 8480889969580968568L;

	protected List actions = new ArrayList();

    /**
     * this list maintained internally to allow for proper xml serialization.
     * All common-action elements in the XML file are expanded into ActionDescriptors
     * and are available via getActions()
     */
    protected List commonActions = new ArrayList();
    protected List permissions = new ArrayList();
    protected List postFunctions = new ArrayList();
    protected List preFunctions = new ArrayList();
    protected Map metaAttributes = new HashMap();
    @Expose
    protected String name;
    protected boolean hasActions = false;
      
    //~ Constructors ///////////////////////////////////////////////////////////

    /**
     * 
     */
   public StepDescriptor() {
    }

   
    /** sets parent */
    public  StepDescriptor(org.dom4j.Element element) {
    	super(element);this.init(element);
    }

    //~ Methods ////////////////////////////////////////////////////////////////

    public ActionDescriptor getAction(int id) {
        for (Iterator iterator = actions.iterator(); iterator.hasNext();) {
            ActionDescriptor action = (ActionDescriptor) iterator.next();

            if (action.getId() == id) {
                return action;
            }
        }

        return null;
    }

    
    
    
    
    
    public List getActions() {
    	return actions;
    }   
    
    public List getCommonActions() {
        return commonActions;
    }

    public void setMetaAttributes(Map metaAttributes) {
        this.metaAttributes = metaAttributes;
    }
	
	public Map getMetaAttributes() {
        return metaAttributes;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    
    
    
    
    
    public List getPermissions() {
        return permissions;
    }

    public void setPostFunctions(List postFunctions) {
        this.postFunctions = postFunctions;
    }

    
    
    
    
    
    public List getPostFunctions() {
        return postFunctions;
    }

    public void setPreFunctions(List preFunctions) {
        this.preFunctions = preFunctions;
    }

    
    
    
    
    
    public List getPreFunctions() {
        return preFunctions;
    }

    
    
    
	public boolean isHasActions() {
		return hasActions;
	}

	/**
	 * 
	 */
	public void setHasActions(boolean hasActions) {
		this.hasActions = hasActions;
	}

	/**
	 * 
	 */
	public void setActions(List actions) {
		this.actions = actions;
	}

	/**
	 * 
	 */
	public void setCommonActions(List commonActions) {
		this.commonActions = commonActions;
	}

	/**
	 * 
	 */
	public void setPermissions(List permissions) {
		this.permissions = permissions;
	}

	/**
     * Remove all common and regular actions for this step.
     */
    public void removeActions() {
        commonActions.clear();
        actions.clear();
        hasActions = false;
    }

    public boolean resultsInJoin(int join) {
        for (Iterator iterator = actions.iterator(); iterator.hasNext();) {
            ActionDescriptor actionDescriptor = (ActionDescriptor) iterator.next();

            if (actionDescriptor.getUnconditionalResult().getJoin() == join) {
                return true;
            }

            List results = actionDescriptor.getConditionalResults();

            for (Iterator iterator2 = results.iterator(); iterator2.hasNext();) {
                ConditionalResultDescriptor resultDescriptor = (ConditionalResultDescriptor) iterator2.next();

                if (resultDescriptor.getJoin() == join) {
                    return true;
                }
            }
        }

        return false;
    }

    public void validate() throws InvalidWorkflowDescriptorException {
        if ((commonActions.size() == 0) && (actions.size() == 0) && hasActions) {
            throw new InvalidWorkflowDescriptorException("Step '" + name + "' actions element must contain at least one action or common-action");
        }

        if (getId() == -1) {
            throw new InvalidWorkflowDescriptorException("Cannot use a step ID of -1 as it is a reserved value");
        }

        ValidationUtils.validate(actions);
        ValidationUtils.validate(permissions);
        ValidationUtils.validate(preFunctions);
        ValidationUtils.validate(postFunctions);

        Iterator iter = commonActions.iterator();

        while (iter.hasNext()) {
            Object o = iter.next();

            try {
                Integer actionId = new Integer(o.toString());
                ActionDescriptor commonActionReference = (ActionDescriptor) ((WorkflowDescriptor) getParent()).getCommonActions().get(actionId);

                if (commonActionReference == null) {
                    throw new InvalidWorkflowDescriptorException("Common action " + actionId + " specified in step " + getName() + " does not exist");
                }
            } catch (NumberFormatException ex) {
                throw new InvalidWorkflowDescriptorException("Common action " + o + " is not a valid action ID");
            }
        }
    }
  
    //dom4f init
    @Override
    protected void init(org.dom4j.Element step) {
    	try {
    		this.setId(Integer.parseInt(step.attributeValue("id")));
    	} catch (Exception ex) {
    		throw new IllegalArgumentException("Invalid step id value " + step.attributeValue("id"));
    	}
    	
    	name = step.attributeValue("name");    	
    	// set up pre-functions - OPTIONAL
        super.buildElement(step, "pre-functions", "function", FunctionDescriptor.class, this.preFunctions, this);
    	
    	// set up permissions - OPTIONAL
        super.buildElement(step, "external-permissions", "permission", PermissionDescriptor.class, this.permissions, this);
    	
    	// set up actions - OPTIONAL
    	super.buildElement(step, "actions", "action", ActionDescriptor.class, this.actions,this, new BuildCallback(){

			@Override
			public void doExecute(Object obj, org.dom4j.Element element) {
				hasActions = true;
				
			}
    		
    	});       
       
    	super.buildElement(step, "actions", "common-action", ActionDescriptor.class, this.commonActions, this, new BuildCallback(){

			@Override
			public void doExecute(Object obj, org.dom4j.Element commonAction) {
				WorkflowDescriptor workflowDescriptor = (WorkflowDescriptor) getParent();
				try {
    				Integer actionId = new Integer(commonAction.attributeValue("id"));
    				
    				ActionDescriptor commonActionReference = (ActionDescriptor) workflowDescriptor.getCommonActions().get(actionId);
    				
    				if (commonActionReference != null) {
    					actions.add(commonActionReference);
    				}
    				commonActions.add(actionId);
    			} catch (Exception ex) {
    				//log.warn("Invalid common actionId:" + ex);
    			}
			}
    		
    	}); 
         	
    	// set up post-functions - OPTIONAL
    	super.buildElement(step, "post-functions", "function", FunctionDescriptor.class, this.postFunctions, this);
    	
    }   
}
